<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>BI Dashboard Demo</title>
  <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
  <style>
    body { font-family: '微软雅黑', Arial, sans-serif; background: #f7fafd; margin: 0; padding: 0; }
    .container { max-width: 1200px; margin: 0 auto; padding: 32px 16px; }
    .filter-row { display: flex; gap: 24px; align-items: center; margin-bottom: 32px; }
    .filter-row label { font-size: 16px; margin-right: 8px; }
    .filter-row select { font-size: 16px; padding: 6px 18px; border-radius: 8px; border: 1px solid #ececec; }
    .card-row { display: flex; gap: 24px; margin-bottom: 32px; }
    .card { background: #fff; border-radius: 16px; box-shadow: 0 2px 12px 0 rgba(80,120,200,0.06); padding: 28px 32px; flex: 1; min-width: 180px; }
    .card-title { font-size: 18px; font-weight: bold; color: #4079ED; margin-bottom: 12px; }
    .card-value { font-size: 32px; font-weight: bold; color: #222; margin-bottom: 4px; }
    .card-desc { font-size: 14px; color: #888; }
    .chart-section { background: #fff; border-radius: 16px; box-shadow: 0 2px 12px 0 rgba(80,120,200,0.06); padding: 24px 32px; margin-bottom: 32px; }
    .section-title { font-size: 18px; font-weight: bold; color: #4079ED; margin-bottom: 16px; }
    .flex-row { display: flex; gap: 32px; }
    .echart-box { width: 400px; height: 260px; }
    .table-section { background: #fff; border-radius: 16px; box-shadow: 0 2px 12px 0 rgba(80,120,200,0.06); padding: 24px 32px; margin-bottom: 32px; }
    table { width: 100%; border-collapse: collapse; margin-bottom: 0; }
    th, td { padding: 10px 8px; text-align: center; font-size: 15px; border-bottom: 1px solid #ececec; }
    th { background: #f3f6fa; color: #4079ED; font-weight: 600; }
    tr:last-child td { border-bottom: none; }
    .badge { display: inline-block; min-width: 40px; padding: 2px 10px; border-radius: 8px; font-size: 14px; text-align: center; }
    .badge.blue { background: #F0F9FF; color: #0095FF; border: 1px solid #0095FF; }
    .badge.green { background: #F0FDF4; color: #00E58F; border: 1px solid #00E58F; }
    .badge.orange { background: #FEF6E6; color: #FF8900; border: 1px solid #FF8900; }
    @media (max-width: 900px) {
      .flex-row, .card-row { flex-direction: column; gap: 16px; }
      .echart-box { width: 100%; min-width: 0; }
    }
  </style>
</head>
<body>
  <div class="container">
    <!-- 全局筛选条件 -->
    <div class="filter-row">
      <label for="departmentSelect">部门：</label>
      <select id="departmentSelect"></select>
      <label for="staffSelect">销售员：</label>
      <select id="staffSelect"></select>
    </div>
    <!-- 业绩统计卡片 -->
    <div class="card-row" id="performanceCards"></div>
    <!-- 渠道占比+数据统计 -->
    <div class="flex-row">
      <div class="chart-section" style="flex:1;">
        <div class="section-title">渠道占比</div>
        <div id="channelPie" class="echart-box"></div>
        <div id="channelLegend"></div>
      </div>
      <div class="chart-section" style="flex:1;">
        <div class="section-title">数据统计</div>
        <div id="dataBar" class="echart-box"></div>
      </div>
    </div>
    <!-- 发货客户数 -->
    <div class="chart-section">
      <div class="section-title">发货客户数</div>
      <div id="customerBar" class="echart-box"></div>
    </div>
    <!-- 客户排名 -->
    <div class="table-section">
      <div class="section-title">客户排名</div>
      <table>
        <thead>
          <tr><th>#</th><th>销售员</th><th>计费重</th><th>实际重量</th><th>CBM</th><th>泡比</th></tr>
        </thead>
        <tbody id="customerTableBody"></tbody>
      </table>
    </div>
    <!-- 风险预警 -->
    <div class="table-section">
      <div class="section-title">风险预警</div>
      <table>
        <thead>
          <tr><th>#</th><th>销售员</th><th>本周业绩</th><th>上周业绩</th><th>同比率</th></tr>
        </thead>
        <tbody id="riskTableBody"></tbody>
      </table>
    </div>
  </div>
  <script>
    // 1. 全局数据
    var departmentStaffMap = {
      A: [
        { value: 'xiaoming', label: '小名' },
        { value: 'xiaohong', label: '小红' }
      ],
      B: [
        { value: 'zhangsan', label: '张三' },
        { value: 'lisi', label: '李四' }
      ]
    };
    // 业绩、渠道、数据统计、客户数、客户排名、风险预警数据
    var demoData = {
      performance: {
        xiaoming: { value: 12000, desc: '本月业绩', change: '+5%' },
        xiaohong: { value: 9000, desc: '本月业绩', change: '+2%' },
        zhangsan: { value: 15000, desc: '本月业绩', change: '+8%' },
        lisi: { value: 8000, desc: '本月业绩', change: '-1%' }
      },
      channel: {
        xiaoming: [ { name: '国际快递', value: 60 }, { name: '加拿大直航', value: 25 }, { name: '美国空运', value: 10 }, { name: '欧洲铁路', value: 5 } ],
        xiaohong: [ { name: '国际快递', value: 50 }, { name: '加拿大直航', value: 30 }, { name: '美国空运', value: 15 }, { name: '欧洲铁路', value: 5 } ],
        zhangsan: [ { name: '国际快递', value: 40 }, { name: '加拿大直航', value: 35 }, { name: '美国空运', value: 15 }, { name: '欧洲铁路', value: 10 } ],
        lisi: [ { name: '国际快递', value: 55 }, { name: '加拿大直航', value: 20 }, { name: '美国空运', value: 20 }, { name: '欧洲铁路', value: 5 } ]
      },
      dataStat: {
        xiaoming: [2000, 2500, 1800, 2200, 3000],
        xiaohong: [1500, 1700, 1600, 1800, 2100],
        zhangsan: [3000, 3200, 3100, 3300, 3500],
        lisi: [1200, 1400, 1300, 1500, 1600]
      },
      customerCount: {
        xiaoming: [10, 12, 8, 11, 15],
        xiaohong: [7, 8, 6, 9, 10],
        zhangsan: [15, 16, 14, 17, 18],
        lisi: [6, 7, 5, 8, 9]
      },
      customerRanking: {
        xiaoming: [
          { name: '客户A', weight: 3000, real: 2800, cbm: 120, ratio: 25 },
          { name: '客户B', weight: 2500, real: 2400, cbm: 100, ratio: 24 },
          { name: '客户C', weight: 2000, real: 1900, cbm: 90, ratio: 21 }
        ],
        xiaohong: [
          { name: '客户D', weight: 2200, real: 2100, cbm: 80, ratio: 26 },
          { name: '客户E', weight: 1800, real: 1700, cbm: 70, ratio: 24 }
        ],
        zhangsan: [
          { name: '客户F', weight: 3500, real: 3400, cbm: 130, ratio: 27 },
          { name: '客户G', weight: 3200, real: 3100, cbm: 120, ratio: 25 }
        ],
        lisi: [
          { name: '客户H', weight: 1600, real: 1500, cbm: 60, ratio: 25 },
          { name: '客户I', weight: 1400, real: 1300, cbm: 55, ratio: 23 }
        ]
      },
      riskAlerts: {
        xiaoming: [ { name: '客户A', week: 1200, last: 1000, rate: '+20%' } ],
        xiaohong: [ { name: '客户D', week: 900, last: 950, rate: '-5%' } ],
        zhangsan: [ { name: '客户F', week: 1500, last: 1400, rate: '+7%' } ],
        lisi: [ { name: '客户H', week: 800, last: 850, rate: '-6%' } ]
      }
    };
    // 2. 初始化下拉框
    var departmentSelect = document.getElementById('departmentSelect');
    var staffSelect = document.getElementById('staffSelect');
    function initDepartment() {
      departmentSelect.innerHTML = '';
      var defaultOpt = document.createElement('option');
      defaultOpt.value = '';
      defaultOpt.textContent = '请选择部门';
      departmentSelect.appendChild(defaultOpt);
      Object.keys(departmentStaffMap).forEach(function(deptKey) {
        var opt = document.createElement('option');
        opt.value = deptKey;
        opt.textContent = deptKey + '部门';
        departmentSelect.appendChild(opt);
      });
    }
    function updateStaffOptions() {
      var val = departmentSelect.value;
      staffSelect.innerHTML = '';
      var defaultOpt = document.createElement('option');
      defaultOpt.value = '';
      defaultOpt.textContent = '请选择销售员';
      staffSelect.appendChild(defaultOpt);
      if (val && departmentStaffMap[val]) {
        departmentStaffMap[val].forEach(function(staff) {
          var opt = document.createElement('option');
          opt.value = staff.value;
          opt.textContent = staff.label;
          staffSelect.appendChild(opt);
        });
      }
    }
    // 3. 渲染所有模块
    function getCurrentStaff() {
      var dept = departmentSelect.value;
      var staff = staffSelect.value;
      if (staff) return staff;
      // 若未选销售员，默认选部门下第一个
      if (dept && departmentStaffMap[dept] && departmentStaffMap[dept][0]) return departmentStaffMap[dept][0].value;
      // 默认第一个部门第一个销售员
      var firstDept = Object.keys(departmentStaffMap)[0];
      return departmentStaffMap[firstDept][0].value;
    }
    function renderPerformance() {
      var staff = getCurrentStaff();
      var data = demoData.performance[staff];
      var html = `<div class="card">
        <div class="card-title">业绩统计</div>
        <div class="card-value">${data.value}</div>
        <div class="card-desc">${data.desc} (${data.change})</div>
      </div>`;
      document.getElementById('performanceCards').innerHTML = html;
    }
    function renderChannelPie() {
      var staff = getCurrentStaff();
      var data = demoData.channel[staff];
      var chart = echarts.init(document.getElementById('channelPie'));
      chart.setOption({
        tooltip: { trigger: 'item' },
        legend: { show: false },
        series: [{
          name: '渠道占比', type: 'pie', radius: ['40%', '70%'],
          label: { show: true, formatter: '{b}: {d}%' },
          data: data.map(item => ({ value: item.value, name: item.name }))
        }]
      });
      // 图例
      var legendHtml = data.map(item => `<span style="display:inline-block;width:12px;height:12px;border-radius:50%;background:#4079ED;margin-right:6px;"></span>${item.name}：${item.value}%`).join(' &nbsp; ');
      document.getElementById('channelLegend').innerHTML = legendHtml;
    }
    function renderDataBar() {
      var staff = getCurrentStaff();
      var data = demoData.dataStat[staff];
      var chart = echarts.init(document.getElementById('dataBar'));
      chart.setOption({
        tooltip: { trigger: 'axis' },
        xAxis: { type: 'category', data: ['第一周','第二周','第三周','第四周','第五周'] },
        yAxis: { type: 'value' },
        series: [{ name: '计费重', type: 'bar', data: data, itemStyle: { color: '#4079ED' } }]
      });
    }
    function renderCustomerBar() {
      var staff = getCurrentStaff();
      var data = demoData.customerCount[staff];
      var chart = echarts.init(document.getElementById('customerBar'));
      chart.setOption({
        tooltip: { trigger: 'axis' },
        xAxis: { type: 'category', data: ['第一周','第二周','第三周','第四周','第五周'] },
        yAxis: { type: 'value' },
        series: [{ name: '客户数', type: 'bar', data: data, itemStyle: { color: '#3CD856' } }]
      });
    }
    function renderCustomerTable() {
      var staff = getCurrentStaff();
      var data = demoData.customerRanking[staff];
      var tbody = document.getElementById('customerTableBody');
      tbody.innerHTML = '';
      data.forEach((row, i) => {
        var tr = document.createElement('tr');
        tr.innerHTML = `<td>${i+1}</td><td>${row.name}</td><td>${row.weight}</td><td>${row.real}</td><td>${row.cbm}</td><td>${row.ratio}</td>`;
        tbody.appendChild(tr);
      });
    }
    function renderRiskTable() {
      var staff = getCurrentStaff();
      var data = demoData.riskAlerts[staff];
      var tbody = document.getElementById('riskTableBody');
      tbody.innerHTML = '';
      data.forEach((row, i) => {
        var color = row.rate.startsWith('+') ? 'green' : 'orange';
        var tr = document.createElement('tr');
        tr.innerHTML = `<td>${i+1}</td><td>${row.name}</td><td>${row.week}</td><td>${row.last}</td><td><span class="badge ${color}">${row.rate}</span></td>`;
        tbody.appendChild(tr);
      });
    }
    function renderAll() {
      renderPerformance();
      renderChannelPie();
      renderDataBar();
      renderCustomerBar();
      renderCustomerTable();
      renderRiskTable();
    }
    // 4. 事件绑定
    departmentSelect.addEventListener('change', function() {
      updateStaffOptions();
      renderAll();
    });
    staffSelect.addEventListener('change', renderAll);
    // 5. 初始化
    initDepartment();
    updateStaffOptions();
    renderAll();
  </script>
</body>
</html> 